#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/buffer_head.h>

#include "e2pfs.h"

struct dentry *e2pfs_lookup(struct inode *parent_inode,
			       struct dentry *child_dentry, unsigned int flags)
{
	return NULL;
}

static struct inode_operations e2pfs_inode_ops = {
	.lookup = e2pfs_lookup,
};

static struct file_operations e2pfs_dir_ops = {
};

struct inode* e2pfs_get_inode(struct super_block *sb, const struct inode *dir, 
							umode_t mode)
{
	struct inode *inode = new_inode(sb);

	if (!inode) 
		return NULL;

	inode->i_ino = get_next_ino();
	inode_init_owner(inode, dir, mode);

	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);

	switch (mode & S_IFMT) {
		case S_IFDIR:
			inc_nlink(inode);
			break;
		case S_IFREG:
			break;
		default:
			/* for now we don't support anything other than
			 * directories and regular files. */
			printk(KERN_ERR "e2pfs don't support this mode!\n");
			return NULL;
			break;
	}
	return inode;

}

static int e2pfs_fill_super(struct super_block *sb, void *data,
				 int silent)
{
	struct inode* root;
	struct buffer_head *bh;
	struct e2pfs_super_block *e2pfs_sb;

	bh = (struct buffer_head *)sb_bread(sb, 0);
	e2pfs_sb = (struct e2pfs_super_block *)bh->b_data;

	if (!bh) {
		printk(KERN_ERR "get superblock failed\n");
		return -EINVAL;
	}

	if (unlikely(e2pfs_sb->magic != E2PFS_MAGIC)) {
		printk(KERN_ERR "The filesystem is not't e2pfs.\n");
		return -EPERM;
	}

	if (unlikely(e2pfs_sb->block_size != E2PFS_BLOCK_SIZE)) {
		printk(KERN_ERR "The filesystem block size not match.\n");
		return -EPERM;
	}

	printk(KERN_INFO "magic : %08x\n", e2pfs_sb->magic);
	printk(KERN_INFO "blocksize : %d\n", e2pfs_sb->block_size);

	root = e2pfs_get_inode(sb, NULL, S_IFDIR);
	root->i_op = &e2pfs_inode_ops;
	root->i_fop = &e2pfs_dir_ops;
	sb->s_root = d_make_root(root);
	if (!sb->s_root)
		return -ENOMEM;

	return 0;
}

void e2pfs_kill_sb(struct super_block *sb)
{
	printk(KERN_INFO "e2pfs unmount succesful!\n");
	kill_block_super(sb);
}

static struct dentry *e2pfs_mount(struct file_system_type *fs_type, int flags,
					const char *dev_name, void *data)
{
		return  mount_bdev(fs_type, flags, dev_name, data, e2pfs_fill_super);
}

struct file_system_type e2pfs_fs_type = {
	.owner 		= THIS_MODULE,
	.name  		= "e2pfs",
	.mount 		= e2pfs_mount,
	.kill_sb	= e2pfs_kill_sb,
};

static int __init e2pfs_init(void)
{
	int ret;
	
	printk(KERN_INFO "%s\n", __func__);
	
	ret = register_filesystem(&e2pfs_fs_type);
	if (ret < 0)
		printk(KERN_ERR "Register e2pfs failed\n");

	return ret;
}

static void e2pfs_exit(void)
{
	printk(KERN_INFO "%s\n", __func__);
	unregister_filesystem(&e2pfs_fs_type);
}

module_init(e2pfs_init);
module_exit(e2pfs_exit);
MODULE_LICENSE("GPL");
